#include "sw_dlink.h"
#include "sw_stack.h"
#include "sw_deque.h"
#include "unistd.h"

#define printdlink(tag, head) { \
    printf(tag); \
    dlink_foreach(cur, head) { \
        printf("%d ", cur->data); \
    } \
    printf("\n");\
}

struct T {
    struct T* next;
    struct T* prev;
    int data;
    char filename[256];
};
struct T* head;

bool find(struct T* cur, void *data)
{
    if (cur->data == 5) {
        return true;
    }
    return false;
}

#define get_struct(__data, __filename) ({ \
    struct T* __cur = new(struct T, .data = __data); \
    strncpy(__cur->filename, __filename, sizeof(__cur->filename));\
    __cur;})

int link_cmp(struct T* a, struct T* b, void *arg)
{
    return a->data - b->data;
}

void test()
{
    char filename[256];
    strncpy(filename, "signway", sizeof(filename));
    struct T* head = dlink_init();
    printf("---------------dlink_sort-----------------\n");
    dlink_clear(head, nullptr, nullptr);
    srand(time(NULL));
    for (int i = 0; i < 5000000; i++) {
        dlink_push_back(head, get_struct(rand() % 100000, filename));
    }
    printf("%d-------------------------------------------\n", __LINE__);
    // printdlink("排序前head: ", head);
    dlink_sort(head, link_cmp, nullptr);
    // printdlink("排序后head: ", head);

    dlink_destory(head, nullptr, nullptr);

    printf("%d----------------destory-----------------\n", __LINE__);
}

void test_stack()
{
    struct T* head = stack_init();
    stack_push(head, get_struct(rand() % 100000, "p1"));
    stack_push(head, get_struct(rand() % 100000, "p2"));
    stack_push(head, get_struct(rand() % 100000, "p3"));
    stack_push(head, get_struct(rand() % 100000, "p4"));

    while(!stack_empty(head)) {
        struct T* temp = stack_pop(head);
        printf("%s ", temp->filename);
    }
    printf("\n");
}

void test_dlink()
{
    char filename[256];
    struct T* cur = nullptr;
    head = dlink_init();

    dlink_push_front(head, get_struct(1, "hello 1"));
    dlink_push_front(head, get_struct(2, "hello 2"));
    dlink_push_front(head, get_struct(3, "hello 3"));
    dlink_push_front(head, get_struct(4, "hello 3"));
    printdlink("head: ", head);

    strncpy(filename, "signway", sizeof(filename));
    dlink_push_back(head, get_struct(5, filename));
    dlink_push_back(head, get_struct(5, "hello 6"));
    printdlink("head: ", head);

    dlink_push_index(head, get_struct(6, "hello 6"), 0);
    dlink_push_index(head, get_struct(7, "hello 7"), 2);
    dlink_push_index(head, get_struct(8, "hello 8"), 30);
    printdlink("head: ", head);

    struct T *f = dlink_find_first(head, find, nullptr);
    if (f != nullptr) {
        printf("%p:%d|%s\n", f, f->data, f->filename);
    }

    struct T *l = dlink_find_last(head, find, nullptr);
    if (l != nullptr) {
        printf("%p:%d|%s\n", l, l->data, l->filename);
    }

    struct T *fd = dlink_delete_last(head, find, nullptr);
    if (fd != nullptr) {
        printf("%p:%d|%s\n", fd, fd->data, fd->filename);
        free(fd);
    }
    printdlink("head: ", head);

    struct T *p1 = dlink_pop_back(head);
    printf("%d\n", p1->data);
    free(p1);

    printdlink("head: ", head);

    struct T *p2 = dlink_pop_front(head);
    printf("%d\n", p2->data);
    free(p2);

    printdlink("head: ", head);

    // dlink* new_link = dlink_init_from_link(head, sizeof(struct T));
    dlink* new_link = dlink_init_from_range(dlink_begin(head)->next, dlink_end(head)->prev, sizeof(struct T));
    printdlink("new_link: ", new_link);
    printdlink("head: ", head);

    printf("----------------------------\n");
    dlink_splice_head(dlink_front(head)->next, new_link);
    printdlink("new_link: ", new_link);
    printdlink("head: ", head);

    printf("--------------dlink_splice_node--------------\n");
    dlink_splice_node(dlink_front(head), dlink_front(head)->next->next);
    printdlink("head: ", head);

    dlink_push_back(new_link, get_struct(0, filename));
    dlink_push_back(new_link, get_struct(1, filename));
    dlink_push_back(new_link, get_struct(2, filename));
    dlink_push_back(new_link, get_struct(3, filename));
    dlink_push_back(new_link, get_struct(4, filename));
    printdlink("new_link: ", new_link);
    dlink_splice_range(dlink_back(head)->prev, dlink_begin(new_link), dlink_end(new_link));
    printdlink("new_link: ", new_link);
    printdlink("head: ", head);

    dlink_clear(head, nullptr, nullptr);
    dlink_clear(new_link, nullptr, nullptr);
    dlink_push_back(new_link, get_struct(0, filename));
    dlink_push_back(new_link, get_struct(2, filename));
    dlink_push_back(new_link, get_struct(4, filename));
    dlink_push_back(new_link, get_struct(6, filename));
    dlink_push_back(new_link, get_struct(8, filename));

    dlink_push_back(head, get_struct(1, filename));
    dlink_push_back(head, get_struct(3, filename));
    dlink_push_back(head, get_struct(6, filename));
    dlink_push_back(head, get_struct(7, filename));
    printf("------------------------------------------\n");
    printdlink("head: ", head);
    printdlink("new_link: ", new_link);
    printf("---------------dlink_swap-----------------\n");
    dlink_swap(head, new_link);
    printdlink("head: ", head);
    printdlink("new_link: ", new_link);
    printf("---------------dlink_merge-----------------\n");
    dlink_merge(head, new_link, link_cmp, nullptr);
    printdlink("head: ", head);

    printf("---------------dlink_reverse-----------------\n");
    dlink_reverse(head);
    printdlink("head: ", head);
    printf("---------------dlink_sort-----------------\n");
    dlink_push_index(head, get_struct(1, filename), 1);
    dlink_push_index(head, get_struct(3, filename), 5);
    dlink_push_index(head, get_struct(6, filename), 9);
    dlink_push_index(head, get_struct(7, filename), 4);
    printdlink("排序前head: ", head);
    dlink_sort(head, link_cmp, nullptr);
    printdlink("排序后head: ", head);

    test();
    test();

    dlink_destory(head, nullptr, nullptr);
    dlink_destory(new_link, nullptr, nullptr);

    printf("%d----------------destory-----------------\n", __LINE__);
}

void test_deque()
{
    deque* deq = deque_init();
    value_type value = 1;
    deque_push_back(deq, value++);
    deque_push_back(deq, value++);
    deque_push_back(deq, value++);
    deque_push_back(deq, value++);
    deque_push_back(deq, value++);
    deque_push_back(deq, value++);
    deque_push_front(deq, value++);
    deque_push_front(deq, value++);
    deque_push_front(deq, value++);
    deque_push_front(deq, value++);
    deque_push_front(deq, value++);
    deque_push_front(deq, value++);
    printf("---------------------\n");
    deque_foreach(deq);
    deque_destroy(deq);
}

int main(int argc, char const *argv[])
{
    test_deque();
    return 0;
}
